package top.xxyu.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import top.xxyu.qq.QQAuthenticationFilter;
import top.xxyu.qq.QQAuthenticationManager;

@Configuration
public class SpringSecurityConf extends WebSecurityConfigurerAdapter {

    @Autowired
    AjaxAuthenticationEntryPoint authenticationEntryPoint;  //  未登陆时返回 JSON 格式的数据给前端（否则为 html）

    @Autowired
    AjaxAuthenticationSuccessHandler authenticationSuccessHandler;  // 登录成功返回的 JSON 格式数据给前端（否则为 html）

    @Autowired
    AjaxAuthenticationFailureHandler authenticationFailureHandler;  //  登录失败返回的 JSON 格式数据给前端（否则为 html）

    @Autowired
    AjaxLogoutSuccessHandler  logoutSuccessHandler;  // 注销成功返回的 JSON 格式数据给前端（否则为 登录时的 html）

    @Autowired
    AjaxAccessDeniedHandler accessDeniedHandler;    // 无权访问返回的 JSON 格式数据给前端（否则为 403 html 页面）

    @Autowired
    SelfUserDetailsService userDetailsService; // 自定义user

    @Autowired
    JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; // JWT 拦截器

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        // 加入自定义的安全认证
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        /**  http
         // 关闭csrf
         .csrf().disable()
         // .anonymous().disable()
         //.cors().and().httpBasic()
         .authorizeRequests()
         // 任何用户都可以访问URL以"/resources/", equals "/signup", 或者 "/about"开头的URL。
         .antMatchers("/resources/**","/login").permitAll()
         //以 "/admin/" 开头的URL只能由拥有 "ROLE_ADMIN"角色的用户访问。请注意我们使用 hasRole 方法
         .antMatchers("/admin/**").hasRole("ADMIN")
         // 任何以"/db/" 开头的URL需要用户同时具有 "ROLE_ADMIN" 和 "ROLE_DBA"。.
         .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
         // 尚未匹配的任何URL要求用户进行身份验证
         .anyRequest().authenticated()
         .and().formLogin()
         .loginPage("/login")
         // 登陆成功
         .loginProcessingUrl("/login").defaultSuccessUrl("/index",true)
         /**   // 认证成功
         .successHandler(new GoAuthenticationSuccessHandler())
         // 认证失败
         .failureHandler(new GoAuthenticationFailureHandler())
         .and().exceptionHandling()
         // 已经认证的用户访问自己没有权限的资源处理
         .accessDeniedHandler(new GoAccessDeniedHandler())
         // 未经过认证的永固访问受保护的资源
         .authenticationEntryPoint(new GoAuthenticationEntryPoint())**/
        /**.and().logout().permitAll()
         // 注销功能
         //.logoutUrl("/login")
         // 注销之后跳转的URL。默认是/login?logout。具体查看 the JavaDoc文档.
         //  .logoutSuccessUrl("/login")
         // 让你设置定制的 LogoutSuccessHandler。如果指定了这个选项那么logoutSuccessUrl()的设置会被忽略
         // .logoutSuccessHandler()
         // 指定是否在注销时让HttpSession无效。 默认设置为 true。
         .invalidateHttpSession(true)
         // 允许指定在注销成功时将移除的cookie。
         .deleteCookies("\"JSESSIONID\"")
         // cookie 失效时间,默认有效期为14天
         .and().rememberMe()
         .tokenValiditySeconds(1800)
         .key("token_key");*/



        // 去掉 CSRF
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 使用 JWT，关闭token
                .and()

                .httpBasic()

                // 未经过认证的用户访问受保护的资源
                .authenticationEntryPoint(authenticationEntryPoint)

                .and()
                .authorizeRequests()
                // 任何用户都可以访问URL以"/resources/", equals "/signup", 或者 "/about"开头的URL。
                .antMatchers("/resources/**", "/login", "/auth/**","/**").permitAll()
                //swagger 放行
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/images/**").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/v2/api-docs").permitAll()
                .antMatchers("/configuration/ui").permitAll()
                .antMatchers("/configuration/security").permitAll()

                //以 "/admin/" 开头的URL只能由拥有 "ROLE_ADMIN"角色的用户访问。请注意我们使用 hasRole 方法
                .antMatchers("/admin").hasRole("ADMIN")
                .antMatchers("/uuu").access("hasRole('USER') or hasRole('ADMIN') ")
                .anyRequest().authenticated()
                .anyRequest()
                .access("@rbacauthorityservice.hasPermission(request,authentication)") // RBAC 动态 url 认证

                .and()
                .formLogin().usernameParameter("username").passwordParameter("password")
                .and()
                //开启认证
                .formLogin()
                // .loginPage("/login")
                //.loginProcessingUrl("/login").defaultSuccessUrl("/index", true).failureUrl("/login?error")
                // 认证成功
                .successHandler(authenticationSuccessHandler)
                // 认证失败
                .failureHandler(authenticationFailureHandler)
                .permitAll()

                .and()
                .logout()
                .logoutSuccessHandler(logoutSuccessHandler)
                .permitAll();

        // 记住我
        http.rememberMe().rememberMeParameter("remember-me")
                .userDetailsService(userDetailsService).tokenValiditySeconds(300);

        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); // 无权访问 JSON 格式的数据

        // 在 UsernamePasswordAuthenticationFilter 前添加 QQAuthenticationFilter
        http.addFilterAt(qqAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // JWT Filter


    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v2/api-docs",
                "/swagger-resources/configuration/ui",
                "/swagger-resources",
                "/swagger-resources/configuration/security",
                "/swagger-ui.html"
        );
    }

    /**
     * 自定义 QQ登录 过滤器
     */
    private QQAuthenticationFilter qqAuthenticationFilter(){
        QQAuthenticationFilter authenticationFilter = new QQAuthenticationFilter("/login/qq");
        authenticationFilter.setAuthenticationManager(new QQAuthenticationManager());
        return authenticationFilter;
    }
}
